package cn.schoolwow.workflow.module.task.action.service;

import cn.schoolwow.quickdao.domain.DAO;
import cn.schoolwow.quickdao.domain.transaction.Transaction;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import cn.schoolwow.util.domain.check.instance.CheckInstance;
import cn.schoolwow.util.domain.query.instanceList.QueryInstanceList;
import cn.schoolwow.workflow.domain.task.type.BackTaskRequest;
import cn.schoolwow.workflow.entity.*;
import cn.schoolwow.workflow.module.common.domain.WorkFlowTaskType;
import cn.schoolwow.workflow.module.common.flow.AddWorkFlowHistoryFlow;
import cn.schoolwow.workflow.module.task.action.flow.common.CheckWorkFlowTaskExistFlow;
import cn.schoolwow.workflow.module.task.action.flow.common.SetWorkFlowTaskListCommonFlow;
import org.apache.commons.lang3.StringUtils;

import java.util.List;

public class BackTaskServiceFlow implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        checkRequest(flowContext);
        setWorkFlowDefinitionAndInstance(flowContext);
        setPreviousWorkFlowNode(flowContext);

        DAO dao = flowContext.checkInstanceData(DAO.class);
        dao.startTransaction(transaction -> {
            flowContext.putTemporaryInstanceData(transaction, Transaction.class);
            addHistory(flowContext);
            deleteCurrentTask(flowContext);
            deletePreviousTask(flowContext);
            createPreviousTask(flowContext);
            updateWorkFlowInstanceNodeId(flowContext);
        });
    }

    @Override
    public String name() {
        return "回退工作流实例任务服务流程";
    }

    private void checkRequest(FlowContext flowContext){
        BackTaskRequest backTaskRequest = flowContext.checkInstanceData(BackTaskRequest.class);

        CheckInstance.newCheck()
                .notNullCheck(backTaskRequest.taskId, "任务id");
        flowContext.startFlow(new CheckWorkFlowTaskExistFlow())
                .putCurrentCompositeFlowData("taskId", backTaskRequest.taskId)
                .execute();
    }

    private void setWorkFlowDefinitionAndInstance(FlowContext flowContext){
        WorkFlowTask workFlowTask = flowContext.checkInstanceData(WorkFlowTask.class);
        DAO dao = flowContext.checkInstanceData(DAO.class);

        WorkFlowDefinition workFlowDefinition = (WorkFlowDefinition) dao.query(WorkFlowDefinition.class)
                .joinTable(WorkFlowInstance.class, "id", "definitionId")
                .addQuery("id", workFlowTask.getInstanceId())
                .done()
                .execute()
                .getOne();
        flowContext.putTemporaryInstanceData(workFlowDefinition);

        WorkFlowInstance workFlowInstance = dao.fetch(WorkFlowInstance.class, workFlowTask.getInstanceId());
        flowContext.putTemporaryInstanceData(workFlowInstance);
    }

    private void setPreviousWorkFlowNode(FlowContext flowContext){
        WorkFlowTask workFlowTask = flowContext.checkInstanceData(WorkFlowTask.class);
        DAO dao = flowContext.checkInstanceData(DAO.class);

        dao.addRecordString("查询上一个工作流任务");
        WorkFlowNode previousWorkFlowNode = (WorkFlowNode) dao.query(WorkFlowInstance.class)
                .addQuery("id", workFlowTask.getInstanceId())
                .joinTable(WorkFlowNodeJump.class, "definitionId", "definitionId")
                .addQuery("nextNodeId", workFlowTask.getNodeId())
                .joinTable(WorkFlowNode.class, "currentNodeId", "id")
                .addColumn("id")
                .addColumn("name")
                .addColumn("assigner")
                .addTableColumn()
                .done()
                .execute()
                .getOne(WorkFlowNode.class);
        if(null==previousWorkFlowNode){
            throw new IllegalArgumentException("回退任务失败!当前节点没有前驱节点!");
        }
        flowContext.putCurrentFlowData("previousWorkFlowNode", previousWorkFlowNode);
    }

    private void addHistory(FlowContext flowContext){
        WorkFlowTask workFlowTask = flowContext.checkInstanceData(WorkFlowTask.class);
        Transaction transaction = flowContext.checkInstanceData(Transaction.class);

        transaction.addRecordString("添加回退任务历史记录");
        flowContext.startFlow(new AddWorkFlowHistoryFlow())
                .putCurrentCompositeFlowData("workFlowInstanceId", workFlowTask.getInstanceId())
                .putCurrentCompositeFlowData("message", "回退工作流任务["+workFlowTask.getTaskName()+"]")
                .putCurrentCompositeFlowData("assigner", workFlowTask.getAssigner())
                .execute();
    }

    private void deleteCurrentTask(FlowContext flowContext){
        WorkFlowTask workFlowTask = flowContext.checkInstanceData(WorkFlowTask.class);
        Transaction transaction = flowContext.checkInstanceData(Transaction.class);

        transaction.addRecordString("删除当前工作流任务");
        transaction.query(WorkFlowTask.class)
                .addQuery("id", workFlowTask.getId())
                .addQuery("instanceId", workFlowTask.getInstanceId())
                .addQuery("nodeId", workFlowTask.getNodeId())
                .execute()
                .delete();
        transaction.commit();
    }

    private void deletePreviousTask(FlowContext flowContext){
        WorkFlowNode previousWorkFlowNode = flowContext.checkData("previousWorkFlowNode", WorkFlowNode.class);
        Transaction transaction = flowContext.checkInstanceData(Transaction.class);

        transaction.addRecordString("删除当前工作流任务");
        transaction.query(WorkFlowTask.class)
                .addQuery("nodeId", previousWorkFlowNode.getId())
                .execute()
                .delete();
        transaction.commit();
    }

    private void createPreviousTask(FlowContext flowContext){
        WorkFlowNode previousWorkFlowNode = flowContext.checkData("previousWorkFlowNode", WorkFlowNode.class);
        WorkFlowTask workFlowTask = flowContext.checkInstanceData(WorkFlowTask.class);
        Transaction transaction = flowContext.checkInstanceData(Transaction.class);

        flowContext.startFlow(new SetWorkFlowTaskListCommonFlow())
                .putCurrentCompositeFlowInstanceData(previousWorkFlowNode)
                .execute();

        List<WorkFlowTask> previousWorkFlowTaskList = flowContext.getData("workFlowTaskList", List.class);
        if(previousWorkFlowTaskList.isEmpty()){
            return;
        }
        for(WorkFlowTask previousWorkFlowTask:previousWorkFlowTaskList){
            previousWorkFlowTask.setInstanceId(workFlowTask.getInstanceId());
            previousWorkFlowTask.setType(WorkFlowTaskType.AuditTask.value);
        }
        transaction.insert(previousWorkFlowTaskList);

        List<String> assignerList = QueryInstanceList.newQuery(previousWorkFlowTaskList)
                .execute()
                .getSingleFieldValueList("assigner");
        flowContext.startFlow(new AddWorkFlowHistoryFlow())
                .putCurrentCompositeFlowData("workFlowInstanceId", workFlowTask.getInstanceId())
                .putCurrentCompositeFlowData("message", "新增工作流任务["+previousWorkFlowNode.getName()+"]")
                .putCurrentCompositeFlowData("assigner", StringUtils.join(assignerList, ","))
                .execute();

        //TODO 目前暂时不支持并行网关
    }

    private void updateWorkFlowInstanceNodeId(FlowContext flowContext){
        WorkFlowTask workFlowTask = flowContext.checkInstanceData(WorkFlowTask.class);
        WorkFlowNode previousWorkFlowNode = flowContext.checkData("previousWorkFlowNode", WorkFlowNode.class);
        Transaction transaction = flowContext.checkInstanceData(Transaction.class);

        transaction.addRecordString("更新工作流实例当前所在节点");
        transaction.query(WorkFlowInstance.class)
                .addQuery("id", workFlowTask.getInstanceId())
                .addUpdate("workFlowNodeId", previousWorkFlowNode.getId())
                .execute()
                .update();
    }

}
